package com.blue.http.config;

import com.blue.core.file.ClassScanner;
import com.blue.core.util.NumberUtil;
import com.blue.http.annotation.HttpClassHandler;
import com.blue.http.annotation.HttpFilterParser;
import com.blue.http.annotation.HttpParser;
import com.blue.http.invoke.Invoker;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.io.CharArrayWriter;
import java.util.List;
import java.util.Map;

/**
 * HTTP配置
 *
 * @author zhengjin
 * @since 1.0 2018年03月17日
 */
public class HttpConfig implements InitializingBean, ApplicationContextAware
{
	private static Logger logger = LoggerFactory.getLogger(HttpConfig.class);
	public static final String FTL_EXT = ".ftl";

	// 路径配置
	private String path;
	private Map<String, String> pathMap; // 虚拟目录

	// Http 配置
	private ApplicationContext ctx;
	private long maxUploadSize;
	private List<InvokerFilterConfig> filterConfigList;
	private HttpParser parser = HttpParser.getInstance();
	private HttpFilterParser filterParser = HttpFilterParser.getInstance();

	// 方法调用
	private Invoker invoker;

	// 页面配置
	private String ftlRoot;
	private Configuration ftlConfig;

	public HttpConfig()
	{
	}

	public Invoker getInvoker()
	{
		return invoker;
	}

	@Override
	public void afterPropertiesSet() throws Exception
	{
		parser.setApplicationContext(ctx);
		filterParser.setApplicationContext(ctx);
		if (filterConfigList != null && !filterConfigList.isEmpty())
		{
			for (InvokerFilterConfig filterConfig : filterConfigList)
			{
				filterParser.parse(filterConfig);
			}
		}

		invoker = new Invoker(parser, filterParser);

		logger.info("最大文件上传大小：{}", maxUploadSize > 0 ? NumberUtil.byteFormat(maxUploadSize) : "无限制");
		logger.info("应用路径：{}", path);
		if (pathMap != null && !pathMap.isEmpty())
		{
			for (Map.Entry<String, String> entry : pathMap.entrySet())
			{
				logger.info("虚拟目录：{} ==> {}", entry.getKey(), entry.getValue());
			}
		}

		this.initFreeMarker();
	}

	private void initFreeMarker() throws TemplateException
	{
		if (ftlRoot == null || ftlRoot.isEmpty())
		{
			logger.info("FreeMarker 路径：未配置");
			return;
		}

		ftlConfig = new Configuration(Configuration.VERSION_2_3_27);
		ftlConfig.setDefaultEncoding("UTF-8");
		ftlConfig.setClassForTemplateLoading(HttpConfig.class, ftlRoot);

		ftlConfig.setSetting("defaultEncoding", "UTF-8");
		ftlConfig.setSetting("number_format", "#.##");
		ftlConfig.setSetting("datetime_format", "yyyy-MM-dd HH:mm");
		ftlConfig.setSetting("date_format", "yyyy-MM-dd");
		ftlConfig.setSetting("time_format", "HH:mm:ss");

		logger.info("FreeMarker 路径：{}", ftlRoot);
	}

	public String render(String ftl, Map<String, Object> param)
	{
		if (ftlConfig == null)
		{
			logger.error("缺少配置 FreeMarker 模板目录");
			return null;
		}

		String html = null;
		try (CharArrayWriter writer = new CharArrayWriter())
		{
			Template template = ftlConfig.getTemplate(ftl + FTL_EXT);
			template.process(param, writer);
			html = writer.toString();
		}
		catch (Exception e)
		{
			logger.error("渲染页面出错：" + ftl, e);
		}
		return html;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
	{
		this.ctx = applicationContext;
	}

	public String getPath()
	{
		return path;
	}

	public void setPath(String path)
	{
		if (path == null || path.isEmpty())
			return;

		if (!path.startsWith("/"))
			path = "/" + path;

		this.path = path;
	}

	public long getMaxUploadSize()
	{
		return maxUploadSize;
	}

	public HttpParser getParser()
	{
		return parser;
	}

	public HttpFilterParser getFilterParser()
	{
		return filterParser;
	}

	public void setFilterConfigs(List<InvokerFilterConfig> filterConfigList)
	{
		this.filterConfigList = filterConfigList;
	}

	public void setMaxUploadSize(long maxUploadSize)
	{
		this.maxUploadSize = maxUploadSize;
	}

	public void setFtlRoot(String ftlRoot)
	{
		this.ftlRoot = ftlRoot;
	}

	public Map<String, String> getPathMap()
	{
		return pathMap;
	}

	public void setPathMap(Map<String, String> pathMap)
	{
		this.pathMap = pathMap;
	}
}
